"""
调度服务模块

业务逻辑层，协调数据解析、验证、求解和结果处理的完整流程。
提供高级的业务接口和错误处理。
"""

from collections import defaultdict, deque
from typing import Any, Callable, Dict, List, Optional, Union

from . import cpsat_solver, data_parser
from .data_models import ScheduleResult, SolverResult
from .exceptions import SchedulerError, ValidationError

# API扩展类型定义
ApiRequest = Dict[str, Any]  # API请求数据结构
ApiResponse = Dict[str, Any]  # API响应数据结构
ApiHandler = Callable[[ApiRequest], ApiResponse]  # API处理函数类型
MiddlewareFunc = Callable[[ApiRequest], ApiRequest]  # 中间件函数类型


class SchedulerService:
    """调度服务类"""

    def __init__(self) -> None:
        """初始化服务"""
        # API扩展点
        self._api_handlers: Dict[str, ApiHandler] = {}
        self._middleware_stack: List[MiddlewareFunc] = []
        self._event_listeners: Dict[str, List[Callable]] = defaultdict(list)

        # 注册默认API端点
        self._register_default_endpoints()

    def create_optimized_schedule(self, csv_path: str) -> ScheduleResult:
        """
        创建优化的施工计划

        工作流程:
        1. 解析CSV数据
        2. 验证数据完整性
        3. 检查循环依赖
        4. 执行CP-SAT求解
        5. 格式化结果

        Args:
            csv_path: CSV文件路径

        Returns:
            调度结果对象
        """
        try:
            # 1. 解析CSV数据
            project_data = data_parser.parse_project_csv(csv_path)

            # 2. 验证数据完整性
            self.validate_project_data(project_data)

            # 3. 检查循环依赖
            if self.has_circular_dependencies(project_data["precedences"]):
                cycles = self.find_circular_dependencies(project_data["precedences"])
                cycle_descriptions = []
                for cycle in cycles[:3]:  # 只显示前3个循环，避免输出过长
                    cycle_str = " -> ".join(map(str, cycle))
                    cycle_descriptions.append(cycle_str)

                error_msg = "检测到循环依赖关系，无法生成有效的调度计划。"
                if cycle_descriptions:
                    error_msg += f" 循环路径: {'; '.join(cycle_descriptions)}"

                return ScheduleResult(success=False, error=error_msg)

            # 4. 执行CP-SAT求解
            solver_result = cpsat_solver.solve_with_cpsat(project_data)

            # 5. 格式化结果
            if solver_result.is_feasible:
                return self.format_schedule_result(solver_result, project_data)
            else:
                return ScheduleResult(
                    success=False,
                    solver_result=solver_result,
                    error=f"求解失败: {solver_result.status} - {solver_result.error_message or '无法找到可行解'}",
                )

        except Exception as e:
            # 统一异常处理和错误封装
            error_message = self._format_error_message(e)
            return ScheduleResult(success=False, error=error_message)

    def validate_project_data(self, project_data: Dict[str, Any]) -> None:
        """
        验证项目数据完整性

        Args:
            project_data: 项目数据字典

        Raises:
            ValidationError: 数据验证失败
        """
        errors = []

        # 验证必需字段存在
        required_fields = ["activities", "precedences", "resources", "resource_demands"]
        for field in required_fields:
            if field not in project_data:
                errors.append(f"缺少必需字段: {field}")

        if errors:
            raise ValidationError("项目数据结构不完整", "; ".join(errors))

        # 验证activities
        activities = project_data["activities"]
        if not activities:
            raise ValidationError("工序列表不能为空")

        activity_ids = set()
        for activity in activities:
            # 验证必需字段
            if (
                "id" not in activity
                or "name" not in activity
                or "duration" not in activity
            ):
                errors.append(f"工序数据不完整: {activity}")
                continue

            # 验证ID唯一性
            activity_id = activity["id"]
            if activity_id in activity_ids:
                errors.append(f"工序ID重复: {activity_id}")
            activity_ids.add(activity_id)

            # 验证工期
            if activity["duration"] <= 0:
                errors.append(
                    f"工序 {activity_id} 的工期必须大于0，当前值: {activity['duration']}"
                )

        # 验证precedences中引用的ID存在
        precedences = project_data["precedences"]
        for precedence in precedences:
            from_id = precedence.get("from")
            to_id = precedence.get("to")

            if from_id not in activity_ids:
                errors.append(f"前置关系中引用了不存在的工序ID: {from_id}")

            if to_id not in activity_ids:
                errors.append(f"前置关系中引用了不存在的工序ID: {to_id}")

            # 验证依赖类型
            dep_type = precedence.get("type")
            if dep_type not in ["FS", "SS", "FF", "SF"]:
                errors.append(f"无效的依赖类型: {dep_type}")

        # 验证资源需求
        resource_demands = project_data["resource_demands"]
        resources = project_data["resources"]

        for activity_id_str, demands in resource_demands.items():
            try:
                activity_id = int(activity_id_str)
                if activity_id not in activity_ids:
                    errors.append(f"资源需求中引用了不存在的工序ID: {activity_id}")
            except ValueError:
                errors.append(f"资源需求中包含无效的工序ID: {activity_id_str}")

            # 验证资源类型存在
            for resource_type, demand in demands.items():
                if resource_type not in resources:
                    errors.append(
                        f"工序 {activity_id_str} 引用了不存在的资源类型: {resource_type}"
                    )

                # 验证需求量合理性
                if demand <= 0:
                    errors.append(
                        f"工序 {activity_id_str} 对资源 {resource_type} 的需求量必须大于0"
                    )
                elif resource_type in resources and demand > resources[resource_type]:
                    errors.append(
                        f"工序 {activity_id_str} 对资源 {resource_type} 的需求量 ({demand}) "
                        f"超过了可用容量 ({resources[resource_type]})"
                    )

        if errors:
            raise ValidationError("项目数据验证失败", "; ".join(errors))

    def has_circular_dependencies(self, precedences: List[Dict]) -> bool:
        """
        使用拓扑排序检测循环依赖

        Args:
            precedences: 前后置关系列表

        Returns:
            是否存在循环依赖
        """
        if not precedences:
            return False

        # 构建邻接表和入度表
        graph: Dict[int, List[int]] = defaultdict(list)
        in_degree: Dict[int, int] = defaultdict(int)
        all_nodes: set[int] = set()

        # 构建图结构
        for precedence in precedences:
            from_id = precedence["from"]
            to_id = precedence["to"]

            graph[from_id].append(to_id)
            in_degree[to_id] += 1
            all_nodes.add(from_id)
            all_nodes.add(to_id)

        # 初始化所有节点的入度（确保没有依赖关系的节点入度为0）
        for node in all_nodes:
            if node not in in_degree:
                in_degree[node] = 0

        # 拓扑排序 - Kahn算法
        queue = deque([node for node in all_nodes if in_degree[node] == 0])
        processed_count = 0

        while queue:
            current_node = queue.popleft()
            processed_count += 1

            # 处理当前节点的所有邻居
            for neighbor in graph[current_node]:
                in_degree[neighbor] -= 1
                if in_degree[neighbor] == 0:
                    queue.append(neighbor)

        # 如果处理的节点数少于总节点数，说明存在循环依赖
        return processed_count < len(all_nodes)

    def find_circular_dependencies(self, precedences: List[Dict]) -> List[List[int]]:
        """
        查找并返回所有循环依赖路径

        Args:
            precedences: 前后置关系列表

        Returns:
            循环依赖路径列表，每个路径是一个工序ID列表
        """
        if not precedences:
            return []

        # 构建邻接表
        graph = defaultdict(list)
        all_nodes = set()

        for precedence in precedences:
            from_id = precedence["from"]
            to_id = precedence["to"]
            graph[from_id].append(to_id)
            all_nodes.add(from_id)
            all_nodes.add(to_id)

        # 使用DFS检测循环
        visited = set()
        rec_stack = set()
        cycles = []

        def dfs(node: int, path: List[int]) -> bool:
            if node in rec_stack:
                # 找到循环，提取循环路径
                cycle_start = path.index(node)
                cycle = path[cycle_start:] + [node]
                cycles.append(cycle)
                return True

            if node in visited:
                return False

            visited.add(node)
            rec_stack.add(node)
            path.append(node)

            for neighbor in graph[node]:
                if dfs(neighbor, path):
                    return True

            rec_stack.remove(node)
            path.pop()
            return False

        # 对每个未访问的节点执行DFS
        for node in all_nodes:
            if node not in visited:
                dfs(node, [])

        return cycles

    def _validate_schedule_constraints(
        self, solver_result: SolverResult, project_data: Dict[str, Any]
    ) -> List[str]:
        """
        验证生成的调度是否满足所有约束条件

        Args:
            solver_result: 求解结果
            project_data: 项目数据

        Returns:
            验证错误列表，空列表表示验证通过
        """
        errors = []
        schedule = solver_result.schedule

        if not schedule:
            return ["调度结果为空"]

        # 1. 验证前后置关系约束
        precedences = project_data["precedences"]
        for precedence in precedences:
            from_id = precedence["from"]
            to_id = precedence["to"]
            dep_type = precedence["type"]
            lag = precedence["lag"]

            if from_id not in schedule or to_id not in schedule:
                errors.append(f"调度中缺少工序 {from_id} 或 {to_id}")
                continue

            pred_activity = schedule[from_id]
            succ_activity = schedule[to_id]

            # 验证不同类型的依赖关系
            if dep_type == "FS":
                if succ_activity["start_time"] < pred_activity["end_time"] + lag:
                    errors.append(
                        f"FS约束违反: 工序{to_id}开始时间({succ_activity['start_time']}) < "
                        f"工序{from_id}结束时间({pred_activity['end_time']}) + 延时({lag})"
                    )
            elif dep_type == "SS":
                if succ_activity["start_time"] < pred_activity["start_time"] + lag:
                    errors.append(
                        f"SS约束违反: 工序{to_id}开始时间({succ_activity['start_time']}) < "
                        f"工序{from_id}开始时间({pred_activity['start_time']}) + 延时({lag})"
                    )
            elif dep_type == "FF":
                if succ_activity["end_time"] < pred_activity["end_time"] + lag:
                    errors.append(
                        f"FF约束违反: 工序{to_id}结束时间({succ_activity['end_time']}) < "
                        f"工序{from_id}结束时间({pred_activity['end_time']}) + 延时({lag})"
                    )
            elif dep_type == "SF":
                if succ_activity["end_time"] < pred_activity["start_time"] + lag:
                    errors.append(
                        f"SF约束违反: 工序{to_id}结束时间({succ_activity['end_time']}) < "
                        f"工序{from_id}开始时间({pred_activity['start_time']}) + 延时({lag})"
                    )

        # 2. 验证资源约束
        resource_errors = self._validate_resource_constraints(
            solver_result, project_data
        )
        errors.extend(resource_errors)

        # 3. 验证工期一致性
        for activity_id, activity in schedule.items():
            expected_duration = None
            for proj_activity in project_data["activities"]:
                if proj_activity["id"] == activity_id:
                    expected_duration = proj_activity["duration"]
                    break

            if expected_duration is not None:
                actual_duration = activity["end_time"] - activity["start_time"]
                if actual_duration != expected_duration:
                    errors.append(
                        f"工序{activity_id}工期不一致: 期望{expected_duration}，实际{actual_duration}"
                    )

        return errors

    def _validate_resource_constraints(
        self, solver_result: SolverResult, project_data: Dict[str, Any]
    ) -> List[str]:
        """
        验证资源约束是否满足

        Args:
            solver_result: 求解结果
            project_data: 项目数据

        Returns:
            资源约束验证错误列表
        """
        errors = []
        schedule = solver_result.schedule

        if schedule is None:
            return ["调度结果为空"]
        resources = project_data["resources"]
        resource_demands = project_data["resource_demands"]

        # 为每种资源类型验证约束
        for resource_type, capacity in resources.items():
            # 创建时间轴上的资源使用情况
            time_usage: Dict[int, int] = defaultdict(int)

            for activity_id, activity in schedule.items():
                activity_id_str = str(activity_id)
                if activity_id_str in resource_demands:
                    demand = resource_demands[activity_id_str].get(resource_type, 0)

                    if demand > 0:
                        # 在活动的时间段内增加资源使用量
                        for time_point in range(
                            activity["start_time"], activity["end_time"]
                        ):
                            time_usage[time_point] += demand

            # 检查是否有时间点超过资源容量
            for time_point, usage in time_usage.items():
                if usage > capacity:
                    errors.append(
                        f"时间点{time_point}资源{resource_type}使用量({usage})超过容量({capacity})"
                    )

        return errors

    def _calculate_project_summary(
        self, solver_result: SolverResult, project_data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        计算项目摘要信息，包括关键路径和资源利用率

        Args:
            solver_result: 求解结果
            project_data: 项目数据

        Returns:
            项目摘要字典
        """
        schedule = solver_result.schedule
        activities = project_data["activities"]
        precedences = project_data["precedences"]
        resources = project_data["resources"]
        resource_demands = project_data["resource_demands"]

        if schedule is None or solver_result.makespan is None:
            raise ValueError("求解结果不完整")

        # 计算基本统计信息
        total_activities = len(activities)
        makespan = solver_result.makespan

        # 计算关键路径
        critical_path = self._find_critical_path(schedule, precedences, makespan)

        # 计算资源利用率
        resource_utilization = self._calculate_resource_utilization(
            schedule, resources, resource_demands, makespan
        )

        # 计算项目统计
        earliest_start = min(activity["start_time"] for activity in schedule.values())
        latest_end = max(activity["end_time"] for activity in schedule.values())

        # 按开始时间排序的活动列表
        sorted_activities = sorted(
            schedule.values(), key=lambda x: (x["start_time"], x["id"])
        )

        return {
            "total_activities": total_activities,
            "makespan": makespan,
            "project_start": earliest_start,
            "project_end": latest_end,
            "critical_path": critical_path,
            "resource_utilization": resource_utilization,
            "sorted_schedule": sorted_activities,
            "solver_status": solver_result.status,
            "solve_time": solver_result.solve_time,
        }

    def _find_critical_path(
        self, schedule: Dict[int, Dict], precedences: List[Dict], makespan: int
    ) -> List[int]:
        """
        查找关键路径

        Args:
            schedule: 调度结果
            precedences: 前后置关系
            makespan: 项目总工期

        Returns:
            关键路径上的工序ID列表
        """
        # 构建前向和后向邻接表
        forward_graph = defaultdict(list)
        backward_graph = defaultdict(list)

        for precedence in precedences:
            from_id = precedence["from"]
            to_id = precedence["to"]
            forward_graph[from_id].append(to_id)
            backward_graph[to_id].append(from_id)

        # 找到项目结束时间等于makespan的活动（项目终点）
        end_activities = [
            activity_id
            for activity_id, activity in schedule.items()
            if activity["end_time"] == makespan
        ]

        if not end_activities:
            return []

        # 从终点开始反向追踪关键路径
        critical_path: List[int] = []

        def find_path_backward(activity_id: int, path: List[int]) -> None:
            path.append(activity_id)

            # 查找前置活动中结束时间等于当前活动开始时间的（紧前关系）
            current_start = schedule[activity_id]["start_time"]
            critical_predecessors = []

            for pred_id in backward_graph[activity_id]:
                if pred_id in schedule:
                    pred_end = schedule[pred_id]["end_time"]
                    # 考虑延时的影响，找到实际的紧前关系
                    for precedence in precedences:
                        if (
                            precedence["from"] == pred_id
                            and precedence["to"] == activity_id
                            and precedence["type"] == "FS"
                        ):  # 简化处理，主要考虑FS关系

                            expected_start = pred_end + precedence["lag"]
                            if expected_start == current_start:
                                critical_predecessors.append(pred_id)

            # 如果有关键前置活动，继续追踪
            if critical_predecessors:
                # 选择最长路径的前置活动
                longest_pred = max(
                    critical_predecessors, key=lambda x: schedule[x]["end_time"]
                )
                find_path_backward(longest_pred, path)

        # 从一个终点活动开始追踪
        if end_activities:
            find_path_backward(end_activities[0], critical_path)

        # 反转路径，使其从开始到结束
        critical_path.reverse()
        return critical_path

    def _calculate_resource_utilization(
        self,
        schedule: Dict[int, Dict],
        resources: Dict[str, int],
        resource_demands: Dict[str, Dict],
        makespan: int,
    ) -> Dict[str, Dict]:
        """
        计算资源利用率

        Args:
            schedule: 调度结果
            resources: 资源容量
            resource_demands: 资源需求
            makespan: 项目总工期

        Returns:
            资源利用率信息字典
        """
        utilization = {}

        for resource_type, capacity in resources.items():
            # 计算每个时间点的资源使用量
            time_usage: List[int] = [0] * makespan
            total_usage = 0

            for activity_id, activity in schedule.items():
                activity_id_str = str(activity_id)
                if activity_id_str in resource_demands:
                    demand = resource_demands[activity_id_str].get(resource_type, 0)

                    if demand > 0:
                        start_time = activity["start_time"]
                        end_time = activity["end_time"]

                        # 在活动时间段内累加资源使用量
                        for t in range(start_time, min(end_time, makespan)):
                            time_usage[t] += demand
                            total_usage += demand

            # 计算统计信息
            max_usage = max(time_usage) if time_usage else 0
            avg_usage = total_usage / makespan if makespan > 0 else 0

            # 计算利用率百分比
            max_utilization = (max_usage / capacity * 100) if capacity > 0 else 0
            avg_utilization = (avg_usage / capacity * 100) if capacity > 0 else 0

            # 计算资源空闲时间
            idle_periods = []
            current_idle_start = None

            for t in range(makespan):
                if time_usage[t] == 0:
                    if current_idle_start is None:
                        current_idle_start = t
                else:
                    if current_idle_start is not None:
                        idle_periods.append((current_idle_start, t - 1))
                        current_idle_start = None

            # 处理最后的空闲期
            if current_idle_start is not None:
                idle_periods.append((current_idle_start, makespan - 1))

            utilization[resource_type] = {
                "capacity": capacity,
                "max_usage": max_usage,
                "avg_usage": round(avg_usage, 2),
                "max_utilization_percent": round(max_utilization, 2),
                "avg_utilization_percent": round(avg_utilization, 2),
                "idle_periods": idle_periods,
                "time_usage": time_usage,
            }

        return utilization

    def format_schedule_result(
        self, solver_result: SolverResult, project_data: Dict[str, Any]
    ) -> ScheduleResult:
        """
        格式化调度结果

        Args:
            solver_result: CP-SAT求解结果
            project_data: 原始项目数据

        Returns:
            格式化的调度结果
        """
        try:
            # 验证求解结果
            if not solver_result.has_solution:
                return ScheduleResult(
                    success=False,
                    solver_result=solver_result,
                    error=f"求解器未返回有效解: {solver_result.status}",
                )

            # 验证生成的调度是否满足约束条件
            validation_errors = self._validate_schedule_constraints(
                solver_result, project_data
            )
            if validation_errors:
                return ScheduleResult(
                    success=False,
                    solver_result=solver_result,
                    error=f"调度结果验证失败: {'; '.join(validation_errors)}",
                )

            # 计算项目摘要信息
            project_summary = self._calculate_project_summary(
                solver_result, project_data
            )

            return ScheduleResult(
                success=True,
                solver_result=solver_result,
                project_summary=project_summary,
            )

        except Exception as e:
            return ScheduleResult(
                success=False,
                solver_result=solver_result,
                error=f"格式化调度结果时出错: {str(e)}",
            )

    def _format_error_message(self, error: Exception) -> str:
        """
        格式化错误消息，提供用户友好的错误信息

        Args:
            error: 异常对象

        Returns:
            格式化的错误消息
        """
        if isinstance(error, ValidationError):
            return f"数据验证错误: {error.message}"
        elif isinstance(error, SchedulerError):
            return f"调度错误: {error.message}"
        elif isinstance(error, FileNotFoundError):
            return f"文件不存在: {str(error)}"
        elif isinstance(error, PermissionError):
            return f"文件访问权限错误: {str(error)}"
        else:
            return f"系统错误: {str(error)}"

    # API扩展接口方法

    def register_api_handler(self, endpoint: str, handler: ApiHandler) -> None:
        """
        注册API处理函数

        Args:
            endpoint: API端点路径
            handler: 处理函数

        Example:
            service.register_api_handler("/api/v1/schedule", custom_schedule_handler)
        """
        self._api_handlers[endpoint] = handler

    def add_middleware(self, middleware: MiddlewareFunc) -> None:
        """
        添加中间件

        Args:
            middleware: 中间件函数

        Example:
            service.add_middleware(authentication_middleware)
        """
        self._middleware_stack.append(middleware)

    def add_event_listener(self, event: str, listener: Callable) -> None:
        """
        添加事件监听器

        Args:
            event: 事件名称
            listener: 监听器函数

        Example:
            service.add_event_listener("schedule_completed", log_completion)
        """
        self._event_listeners[event].append(listener)

    def emit_event(self, event: str, data: Any = None) -> None:
        """
        触发事件

        Args:
            event: 事件名称
            data: 事件数据
        """
        for listener in self._event_listeners.get(event, []):
            try:
                listener(data)
            except Exception as e:
                # 事件处理错误不应影响主流程
                print(f"事件监听器错误 ({event}): {e}")

    def handle_api_request(
        self, endpoint: str, request_data: ApiRequest
    ) -> ApiResponse:
        """
        处理API请求

        Args:
            endpoint: API端点
            request_data: 请求数据

        Returns:
            API响应数据

        Note:
            这是未来API服务化的核心接口
        """
        try:
            # 应用中间件
            processed_request = request_data
            for middleware in self._middleware_stack:
                processed_request = middleware(processed_request)

            # 查找处理函数
            if endpoint not in self._api_handlers:
                return {
                    "success": False,
                    "error": f"未找到API端点: {endpoint}",
                    "code": 404,
                }

            # 执行处理函数
            handler = self._api_handlers[endpoint]
            response = handler(processed_request)

            # 触发请求完成事件
            self.emit_event(
                "api_request_completed", {"endpoint": endpoint, "response": response}
            )

            return response

        except Exception as e:
            error_response = {
                "success": False,
                "error": str(e),
                "code": 500,
            }

            # 触发错误事件
            self.emit_event(
                "api_request_error", {"endpoint": endpoint, "error": str(e)}
            )

            return error_response

    def _register_default_endpoints(self) -> None:
        """注册默认API端点"""

        def schedule_endpoint(request: ApiRequest) -> ApiResponse:
            """调度优化API端点"""
            try:
                csv_path = request.get("csv_path")
                if not csv_path:
                    return {"success": False, "error": "缺少csv_path参数", "code": 400}

                # 获取扩展参数
                interruptions = request.get("interruptions")
                multi_objective_weights = request.get("multi_objective_weights")
                solver_params = request.get("solver_params")

                # 执行调度优化
                result = self.create_optimized_schedule_extended(
                    csv_path, interruptions, multi_objective_weights, solver_params
                )

                if result.success:
                    return {
                        "success": True,
                        "data": {
                            "makespan": result.makespan,
                            "schedule": result.schedule,
                            "summary": result.project_summary,
                        },
                        "code": 200,
                    }
                else:
                    return {"success": False, "error": result.error, "code": 400}

            except Exception as e:
                return {"success": False, "error": str(e), "code": 500}

        def health_endpoint(request: ApiRequest) -> ApiResponse:
            """健康检查API端点"""
            return {
                "success": True,
                "status": "healthy",
                "version": "1.0.0",
                "code": 200,
            }

        def capabilities_endpoint(request: ApiRequest) -> ApiResponse:
            """功能查询API端点"""
            return {
                "success": True,
                "capabilities": {
                    "weather_interruptions": "planned",  # 计划中
                    "multi_objective": "planned",  # 计划中
                    "real_time_updates": "planned",  # 计划中
                    "resource_optimization": "available",  # 可用
                    "dependency_types": ["FS", "SS", "FF", "SF"],
                },
                "code": 200,
            }

        # 注册端点
        self.register_api_handler("/api/v1/schedule", schedule_endpoint)
        self.register_api_handler("/api/v1/health", health_endpoint)
        self.register_api_handler("/api/v1/capabilities", capabilities_endpoint)

    def create_optimized_schedule_extended(
        self,
        csv_path: str,
        interruptions: Optional[List] = None,
        multi_objective_weights: Optional[Dict] = None,
        solver_params: Optional[Dict] = None,
    ) -> ScheduleResult:
        """
        扩展的调度优化方法

        Args:
            csv_path: CSV文件路径
            interruptions: 天气中断列表
            multi_objective_weights: 多目标权重
            solver_params: 求解器参数

        Returns:
            调度结果对象

        Note:
            这是未来扩展功能的主要接口
        """
        try:
            # 触发调度开始事件
            self.emit_event("schedule_started", {"csv_path": csv_path})

            # 1. 解析CSV数据
            project_data = data_parser.parse_project_csv(csv_path)

            # 2. 验证数据完整性
            self.validate_project_data(project_data)

            # 3. 检查循环依赖
            if self.has_circular_dependencies(project_data["precedences"]):
                cycles = self.find_circular_dependencies(project_data["precedences"])
                cycle_descriptions = []
                for cycle in cycles[:3]:
                    cycle_str = " -> ".join(map(str, cycle))
                    cycle_descriptions.append(cycle_str)

                error_msg = "检测到循环依赖关系，无法生成有效的调度计划。"
                if cycle_descriptions:
                    error_msg += f" 循环路径: {'; '.join(cycle_descriptions)}"

                return ScheduleResult(success=False, error=error_msg)

            # 4. 执行扩展的CP-SAT求解
            solver_result = cpsat_solver.solve_with_cpsat(
                project_data, interruptions, multi_objective_weights, solver_params
            )

            # 5. 格式化结果
            if solver_result.is_feasible:
                result = self.format_schedule_result(solver_result, project_data)
                # 触发调度完成事件
                self.emit_event("schedule_completed", {"result": result})
                return result
            else:
                error_msg = f"求解失败: {solver_result.status} - {solver_result.error_message or '无法找到可行解'}"
                # 触发调度失败事件
                self.emit_event("schedule_failed", {"error": error_msg})
                return ScheduleResult(
                    success=False, solver_result=solver_result, error=error_msg
                )

        except Exception as e:
            error_message = self._format_error_message(e)
            # 触发调度错误事件
            self.emit_event("schedule_error", {"error": error_message})
            return ScheduleResult(success=False, error=error_message)


# 全局服务实例
_service = SchedulerService()


def create_optimized_schedule(csv_path: str) -> ScheduleResult:
    """
    便捷函数：创建优化的施工计划

    Args:
        csv_path: CSV文件路径

    Returns:
        调度结果对象
    """
    return _service.create_optimized_schedule(csv_path)
